package com.flejay.dreamrecruiter.dao;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.apache.commons.io.IOUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;

import com.flejay.dreamrecruiter.model.SubTag;
import com.flejay.dreamrecruiter.model.Tag;
import com.flejay.dreamrecruiter.tools.ConfigReaderTool;
import com.flejay.dreamrecruiter.tools.CustomStringUtils;
import com.flejay.dreamrecruiter.tools.IConstantsUtil;
import com.flejay.dreamrecruiter.tools.ILoggingService;
import com.flejay.dreamrecruiter.tools.converter.TextFileConverterTool;

@Singleton
@Named("fileConfigurationLoaderDao")
public class FileConfigurationLoaderDao implements IConfigurationLoaderDao{

	private String prefix = "^\\s*";
	private String allContaining = "(\\s*((\\.|:)(\\s*(:|–|-|—|/))?)?|(\\d+\\s*(–|-|—)\\d+\\s*(:|.|–|-|—|/)?))";

	@Inject
	@Named("logService")
	private ILoggingService logService;
	
	@Override
	public List<Tag> loadTagConfiguration(final String mode, final String language) {
		String conf = language + "_" + mode;
		StringBuffer configFileName = new StringBuffer()
			.append(ConfigReaderTool.FILE_CONFIGURATION_FOLDER)
			.append(conf)
			.append(ConfigReaderTool.FILE_CONFIGURATION_EXTENSION);
		
		Resource resource = new ClassPathResource(configFileName.toString());
		List<Tag> tagList = new ArrayList<Tag>();
		try {
			String file = IOUtils.toString(resource.getInputStream());
			for(String tagLine : file.split(IConstantsUtil.LINE_SEPARATOR)){
				if (!StringUtils.isEmpty(tagLine)){
					String[] splittedContent = tagLine.split(IConstantsUtil.TABULATION);
					if (splittedContent.length != 3){
						throw new IllegalStateException("configuration file is not well formated");
					}
					Tag extractedTag = extractTagValues(splittedContent,conf);
					tagList.add(extractedTag);
				}
			}
		} catch (IOException e) {
			StringBuffer excMessage = new StringBuffer()
				.append("regex configuration file named ")
				.append(configFileName)
				.append(" was not successfully loaded");
			logService.error(this.getClass(), excMessage.toString());
			// on jete une erreur car il s'agit d'un probleme critique
			throw new IllegalStateException(excMessage.toString());
		}
		return tagList;
	}
	
	@Override
	public Map<String,List<SubTag>> loadSubTagsConfiguration(String conf){
		Map<String,List<SubTag>> tagMap = readSubTagConfigFile(conf);
		for (List<SubTag> subTagList : tagMap.values()){
			for (SubTag subTag : subTagList){
				subTag.setRegexp(readSubTagRegex(conf, subTag.getRegexFileName()));
			}
		}
		return tagMap;
	}

	private List<Pattern> readSubTagRegex(String conf, String regexFileName) {
		List<Pattern> res = new ArrayList<Pattern>();
		StringBuffer configFileName = new StringBuffer()
			.append(ConfigReaderTool.REGEX_CONFIGURATION_FOLDER)
			.append(conf).append("/")
			.append(ConfigReaderTool.SUB_REGEX_CONFIGURATION_FOLDER)
			.append("regex/")
			.append(regexFileName);
		
		Resource resource = new ClassPathResource(configFileName.toString());
		// chargement des regexs
		String regexs;
		try {
			regexs = IOUtils.toString(resource.getInputStream());
			for(String regex : regexs.split(IConstantsUtil.LINE_SEPARATOR)){
				if (!StringUtils.isEmpty(regex)){
	    			res.add(Pattern.compile(CustomStringUtils.removeBackLine(regex),Pattern.CASE_INSENSITIVE));
				}
			}
		} catch (IOException e) {
			StringBuffer excMessage = new StringBuffer()
				.append("regex configuration file named ")
				.append(configFileName)
				.append(" was not successfully loaded");
			logService.error(this.getClass(), excMessage.toString());
			// on jete une erreur car il s'agit d'un probleme critique
			throw new IllegalStateException(excMessage.toString());
		}
		return res;
	}

	private Map<String, List<SubTag>> readSubTagConfigFile(String conf) {
		Map<String,List<SubTag>> subTags = new HashMap<String,List<SubTag>>();
		StringBuffer configFileName = new StringBuffer()
			.append(ConfigReaderTool.REGEX_CONFIGURATION_FOLDER)
			.append(conf).append("/")
			.append(ConfigReaderTool.SUB_REGEX_CONFIGURATION_FOLDER)
			.append(ConfigReaderTool.CONFIG_FILE);
	
		Resource resource = new ClassPathResource(configFileName.toString());
		try {
			String currentTag = "";
			for(String tagLine : extractLinesFromResource(resource)){
				if (!StringUtils.isEmpty(tagLine)){
					if (tagLine.startsWith("\t")){
						// subTag
						SubTag subTag = SubTag.getNewInstance();
						String[] splitted = tagLine.split("\t");
						if (splitted.length != 5){
							throw new IllegalStateException("configuration file is not well formated");
						}
						subTag.setLabel(splitted[1]);
						subTag.setRegexFileName(splitted[2]);
						if ("0".equalsIgnoreCase(CustomStringUtils.removeBackLine(splitted[3]))){
							subTag.setAgglomerate(false);
						} else {
							subTag.setAgglomerate(true);
						}
						if ("0".equalsIgnoreCase(CustomStringUtils.removeBackLine(splitted[4]))){
							subTag.setIsolatedStratey(false);
						} else {
							subTag.setIsolatedStratey(true);
						}
						List<SubTag> subTagList = subTags.get(currentTag);
						if (subTagList == null){
							subTagList = new ArrayList<SubTag>();
						}
						subTagList.add(subTag);
						subTags.put(currentTag, subTagList);
					} else {
						// tag
						currentTag = CustomStringUtils.removeBackLine(tagLine);
					}
				}
			}
		} catch (IOException e) {
			handleCriticalErrorLoadingConfigurationFile(configFileName.toString());
		}
		return subTags;
	}
	
	private void handleCriticalErrorLoadingConfigurationFile(String configFileName){
		StringBuffer excMessage = new StringBuffer()
			.append("regex configuration file named ")
			.append(configFileName)
			.append(" was not successfully loaded");
		logService.error(this.getClass(), excMessage.toString());
		// on jete une erreur car il s'agit d'un probleme critique
		throw new IllegalStateException(excMessage.toString());
	}
	
	private String[] extractLinesFromResource(Resource resource) throws IOException {
		String file = IOUtils.toString(resource.getInputStream());
		return file.split(IConstantsUtil.LINE_SEPARATOR);
	}

	@Override
	public List<String> extractTagsFromVerfiedCV(String fileName) {
		List<String> tagsToRemove = (new ArrayList<String>());
		tagsToRemove.add("formation_additionnelle");
		tagsToRemove.add("resume");
		tagsToRemove.add("enseignement");
		tagsToRemove.add("recherche");
		tagsToRemove.add("publications");
		tagsToRemove.add("collaborations");
		
		StringBuffer configFileName = new StringBuffer()
			.append(ConfigReaderTool.FILE_VERIFICATION_FOLDER)
			.append(fileName);
		List<String> res = new ArrayList<String>();
		String content;
		Resource resource = new ClassPathResource(configFileName.toString());
		try {
			content = IOUtils.toString(resource.getInputStream());
		} catch (IOException e) {
			logService.error(this.getClass(), e.toString());
			// on jete une erreur car il s'agit d'un probleme critique
			throw new IllegalStateException(e.toString());
		}
		for(String line : content.split(IConstantsUtil.LINE_SEPARATOR)){
			if (line.matches("(\\s*)(<\\w+>)")){
				String tag = line;
				tag = tag.replaceAll("<", "");
				tag = tag.replaceAll(">", "");
				tag = tag.replaceAll("\\s", "");
				res.add(tag);
			}
		}
		for(String tagToRemove : tagsToRemove){
			res.remove(tagToRemove);
		}
		return res;
	}
	
	@Override
	public List<File> loadVerificationCV() throws IOException {
		List<File> verifiedCVs = new ArrayList<File>();
		Resource resource = new ClassPathResource(ConfigReaderTool.FILE_VERIFICATION_FOLDER);
		final File folder = resource.getFile();
		if (folder.listFiles() != null){
			for (final File fileEntry : folder.listFiles()) {
	    		verifiedCVs.add(fileEntry);
		    }
		}
		return verifiedCVs;
	}
	

	/**
	 * Extract values to construct a full Tag Object
	 * 
	 * @param label
	 * @param splittedContent
	 * @param configFileName
	 * @return
	 */
	private Tag extractTagValues(final String[] splittedContent, final String configFileName) {
		Tag tag = Tag.getNewInstance();
		tag.setLabel(splittedContent[0]);
		if ("1".equalsIgnoreCase(splittedContent[1])){
			tag.setExtract(true);
		} else {
			tag.setExtract(false);
		}
		String sizeO = splittedContent[2].replaceAll("\\r", "");
		tag.setSizeObjective(sizeO);
		tag.setRegexp(extractRegexs(configFileName, tag.getLabel(),REGEX_TYPE.FINDER));
		tag.setEndingPatternList(extractRegexs(configFileName, tag.getLabel(),REGEX_TYPE.STOPPER));
		return tag;
	}

	/**
	 * Extract Precompiled regexs
	 * 
	 * @param configFileName
	 * @param label
	 * @param regexType
	 * @return
	 */
	private List<Pattern> extractRegexs(final String configFileName, final String label, final REGEX_TYPE regexType) {
		List<Pattern> precompiledRegex = new ArrayList<Pattern>();
		// classpath du fichier de configuration de regex à charger
		String stopFolder = "";
		if (REGEX_TYPE.STOPPER.equals(regexType)){
			stopFolder = ConfigReaderTool.REGEX_STOPPER_CONFIGURATION_FOLDER;
		}
		String regexFile = new StringBuffer()
			.append(ConfigReaderTool.REGEX_CONFIGURATION_FOLDER)
			.append(configFileName)
			.append("/")
			.append(stopFolder)
			.append(label)
			.append(ConfigReaderTool.FILE_CONFIGURATION_EXTENSION)
			.toString();
		
		// chargement des regexs
		Resource resource = new ClassPathResource(regexFile);
		String regexs;
		try {
			regexs = IOUtils.toString(resource.getInputStream());
			for(String regex : regexs.split(IConstantsUtil.LINE_SEPARATOR)){
				if (!StringUtils.isEmpty(regex)){
						StringBuffer stringBuf = new StringBuffer();
						stringBuf.append(prefix)
							.append(CustomStringUtils.removeBackLine(regex))
							.append(allContaining);
						precompiledRegex.add(Pattern.compile(stringBuf.toString(),Pattern.CASE_INSENSITIVE));
				}
			}
		} catch (IOException e) {
			StringBuffer excMessage = new StringBuffer()
				.append("regex configuration file named ")
				.append(regexFile)
				.append(" was not successfully loaded");
			logService.error(this.getClass(), excMessage.toString());
			// on jete une erreur car il s'agit d'un probleme critique
			throw new IllegalStateException(excMessage.toString());
		}
		return precompiledRegex;
	}

	/**
	 * Extract sub tags
	 * 
	 * @param mode
	 * @param lang
	 * @param label
	 * @return
	 */
	private List<SubTag> extractSubTags(String conf, String label) {
		List<SubTag> subTags = new ArrayList<SubTag>();
		String regexFile = new StringBuffer()
			.append(ConfigReaderTool.REGEX_CONFIGURATION_FOLDER)
			.append(conf)
			.append("/")
			.append(ConfigReaderTool.SUB_CONFIGURATION_FOLDER)
			.append(label)
			.append("/")
			.toString();
		Resource resource = new ClassPathResource(regexFile);
		try {
			final File folder = new File(resource.getURI());
			if (folder.listFiles() != null){
				for (final File fileEntry : folder.listFiles()) {
					SubTag subTag = SubTag.getNewInstance();
					subTag.setLabel(CustomStringUtils.removeWhiteSpaceAndExtension(fileEntry.getName()));
			    	try {
			    		for(String line : TextFileConverterTool.extractText(fileEntry).split(IConstantsUtil.LINE_SEPARATOR)){
			    			subTag.getRegexp().add(Pattern.compile(CustomStringUtils.removeBackLine(line)));
			    		}
			    		subTags.add(subTag);
					} catch (IOException e) {
						logService.info(this.getClass(), "la lecture du fichier {} a provoqué une erreur. Fichier ignoré", fileEntry);
					}
			    }
			}
		} catch(IOException e){
			//TODO
			e.printStackTrace();
		}
		return subTags;
	}
}
